package net.midnighttd.engine.map;

import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import java.util.HashMap;
import java.util.ArrayList;
import java.awt.image.BufferedImage;

/**
 * Author: Adam Scarr
 * Date: 17/04/2009
 * Time: 8:21:29 PM
 *
 * Reads an XML Tileset and loads up all the tile blocks, finally providing a flyweight factory method for tiles.
 */
public class Tileset {
    private HashMap<String,Tile> tiles = new HashMap<String, Tile>();
    private ArrayList<TileBlock> blocks = new ArrayList<TileBlock>();
    private HashMap<TileSignature, BufferedImage> tilecache = new HashMap<TileSignature, BufferedImage>();
    private int tilewidth;
    private int tileheight;

    public Tileset(Element e) {
        loadFromXML(e);
    }

    public BufferedImage getTile(Map map, int x, int y) {
        if(map.get(x, y) == null) return null;
        
        TileSignature sig = new TileSignature(map, x, y);

        if(tilecache.containsKey(sig)) {
            return tilecache.get(sig);
        }

        for(TileBlock block: blocks) {
            BufferedImage renderedTile = block.getTile(sig);
            if(renderedTile != null) {
                tilecache.put(sig, renderedTile);
                return renderedTile;
            }
        }

        throw new Error("Could not find a tile that matches " + sig.toString() + " used at (" + x + "," + y + ")" );
    }

    private void loadFromXML(Element e) {
        tilewidth = Integer.valueOf(e.getAttribute("tilewidth"));
        tileheight = Integer.valueOf(e.getAttribute("tileheight"));

        NodeList tiles = e.getElementsByTagName("tile");

        for(int i = 0; i < tiles.getLength(); i++) {
            if(tiles.item(i).getNodeType() != Node.ELEMENT_NODE) continue;
            Element tile = (Element)tiles.item(i);

            String name = tile.getAttribute("id");
            boolean passable = Boolean.valueOf(tile.getAttribute("passable"));
            String filename = tile.getAttribute("filename");
            Tile newTile = new Tile(name, passable);
            this.tiles.put(name, newTile);
            blocks.add(new TileBlock(filename, tilewidth, tileheight, newTile));
        }
    }


    public Tile get(String tile) {
        if(tile.isEmpty()) return null;
        if(!tiles.containsKey(tile)) throw new Error("The tile name " + tile + " is not recognized");
        
        return tiles.get(tile);
    }

    public int getTilewidth() {
        return tilewidth;
    }

    public int getTileheight() {
        return tileheight;
    }
}
